<?php
/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/09/04
 * Time: 17:21
 * @link http://www.lmterp.cn
 */

namespace app\common\service\logistics;

use app\common\library\Tools;
use app\common\model\Channel;
use app\common\model\ChannelAllowAttr;
use app\common\model\ChannelAttr;
use app\common\model\ChannelCarrier;
use app\common\model\ChannelCountryQuotation;
use app\common\model\ChannelCountrySettings;
use app\common\model\ChannelExpress;
use app\common\model\ChannelOrders;
use app\common\model\OrdersRules;
use app\common\model\OrdersRulesGroup;
use app\common\model\ChannelSender;
use app\common\model\Orders;
use app\common\service\BaseService;
use app\common\service\channel\BaseChannel;
use think\Db;
use think\exception\DbException;
use think\facade\Log;

class ChannelService extends BaseService
{
    /**
     * 保存订单预报信息
     * @param array $data
     * @return ChannelOrders|null
     * @date 2020/09/05
     * @author longli
     */
    public function saveChannelOrders($data = [])
    {
        $insert = ChannelOrders::getFilterField($data);
        if(empty($insert) || empty($insert['channel_id']) || empty($insert['order_id'])) return null;
        $chOrder = null;
        if(!empty($insert['ch_id'])) $chOrder = ChannelOrders::get($insert['ch_id']);
        if(empty($chOrder) && !empty($insert['track_num']))
            $chOrder = ChannelOrders::get(['channel_id' => $insert['channel_id'], 'order_id' => $insert['order_id'], 'track_num' => $insert['track_num']]);
        if(!empty($chOrder))
        {
            $chOrder->save($insert);
        }
        else
        {
            ChannelOrders::destroy(['channel_id' => $insert['channel_id'], 'order_id' => $insert['order_id']]);
            $chOrder = ChannelOrders::create($insert)->refresh();
        }
        return $chOrder;
    }

    /**
     * 添加渠道
     * @param array $data 渠道信息
     * @return Channel|bool
     * @date 2020/09/18
     * @author longli
     */
    public function addChannel($data = [])
    {
        $cData = Channel::getFilterField($data);
        if(empty($cData)) return false;
        $cData = Tools::trim($cData);
        $channel = null;
        if(isset($cData['channel_id'])) $channel = Channel::get($cData['channel_id']);
        if(!empty($channel))
        {
            $channel->save($cData);
        }
        else
        {
            $channel = Channel::create($cData)->refresh();
        }
        return $channel;
    }

    /**
     * 添加承运商
     * @param array $data 承运商信息
     * @return ChannelCarrier|bool
     * @date 2020/09/18
     * @author longli
     */
    public function addCarrier($data = [])
    {
        $cData = ChannelCarrier::getFilterField($data);
        if(empty($cData)) return false;
        $cData = Tools::trim($cData);
        $carrier = null;
        if(isset($cData['carrier_id'])) $carrier = ChannelCarrier::get($cData['carrier_id']);
        if(!empty($carrier))
        {
            $carrier->save($cData);
        }
        else
        {
            $carrier = ChannelCarrier::create($cData)->refresh();
        }
        return $carrier;
    }

    /**
     * 添加发货人
     * @param array $data 发货人信息
     * @return ChannelSender|bool
     * @date 2020/09/18
     * @author longli
     */
    public function addSender($data = [])
    {
        $sData = ChannelSender::getFilterField($data);
        if(empty($sData)) return false;
        $sData = Tools::trim($sData);
        $sender = null;
        if(isset($sData['sender_id'])) $sender = ChannelSender::get($sData['sender_id']);
        if(!empty($sender))
        {
            $sender->save($sData);
        }
        else
        {
            $sender = ChannelSender::create($sData)->refresh();
        }
        if(!empty($sData['is_default'])) ChannelSender::setDefault($sender, true);
        return $sender;
    }

    /**
     * 添加国内快递
     * @param array $data
     * @return ChannelExpress|false
     * @date 2021/03/04
     * @author longli
     */
    public function addExpress($data = [])
    {
        $eData = ChannelExpress::getFilterField($data);
        if(empty($eData)) return false;
        $eData = Tools::trim($eData);
        $express = null;
        if(isset($eData['express_id'])) $express = ChannelExpress::get($eData['express_id']);
        if(!empty($express))
        {
            $express->save($eData);
        }
        else
        {
            $express = ChannelExpress::create($eData)->refresh();
        }
        return $express;
    }

    /**
     * 添加物流属性
     * @param array $data 属性信息
     * @return ChannelAttr|false
     * @date 2021/08/29
     * @author longli
     */
    public function addAttr($data = [])
    {
        $aData = ChannelAttr::getFilterField($data);
        if(empty($aData)) return false;
        $aData = Tools::trim($aData);
        $attr = null;
        if(isset($aData['attr_id'])) $attr = ChannelAttr::get($aData['attr_id']);
        if(empty($attr) && !empty($aData['code'])) $attr = ChannelAttr::get(["code" => $aData['code']]);
        if(!empty($attr))
        {
            $attr->save($aData);
        }
        else
        {
            $attr = ChannelAttr::create($aData)->refresh();
        }
        return $attr;
    }

    /**
     * 添加渠道国家配置
     * @param array $data 国家配置
     * @param array $quotaion 报价单
     * @return ChannelCountrySettings|false
     * @date 2021/08/29
     * @author longli
     */
    public function addSetting($data = [], $quotaion = [])
    {
        $sData = ChannelCountrySettings::getFilterField($data);
        if(empty($sData)) return false;
        $sData = Tools::trim($sData);
        $setting = null;
        if(isset($sData['setting_id'])) $setting = ChannelCountrySettings::get($sData['setting_id']);
        if(empty($setting) && !empty($sData['channel_id']) && !empty($sData['country_code']))
            $setting = ChannelCountrySettings::get(['channel_id' => $sData['channel_id'], 'country_code' => $sData['country_code']]);
        try
        {
            Db::startTrans();
            if(!empty($setting))
            {
                $setting->save($sData);
            }
            else
            {
                $setting = ChannelCountrySettings::create($sData)->refresh();
            }
            if(!empty($quotaion)) $this->addQuotation($setting, $quotaion);
            Db::commit();
            return $setting;
        }catch(DbException $e)
        {
            Log::info(sprintf("添加渠道报价单错误，提示信息【%s】", $e->getMessage()));
            return false;
        }
    }

    /**
     * 添加报价单
     * @param ChannelCountrySettings $setting 可走国家
     * @param array $quotationData 报价单
     * @return ChannelCountryQuotation|false
     * @date 2021/08/30
     * @author longli
     */
    public function addQuotation($setting, $quotationData = [])
    {
        if(!isset($quotationData[0])) $quotationData = [$quotationData];
        $quotation = null;
        $noid = [];
        foreach($quotationData as $data)
        {
            $quotation = null;
            $qData = ChannelCountryQuotation::getFilterField($data);
            if(empty($qData)) return false;
            if(isset($qData['quotation_id'])) $quotation = ChannelCountryQuotation::get($qData['quotation_id']);
            $qData['setting_id'] = $setting->setting_id;
            $qData['country_code'] = $setting->country_code;
            if(!empty($quotation))
            {
                $quotation->save($qData);
            }
            else
            {
                $quotation = ChannelCountryQuotation::create($qData)->refresh();
            }
            $noid[] = $quotation->quotation_id;
        }
        ChannelCountryQuotation::destroy(function($query) use($setting, $noid)
        {
            $query->where("setting_id", $setting->setting_id)->whereNotIn("quotation_id", $noid);
        });
        return $quotation;
    }

    /**
     * 添加可走属性
     * @param array $data 可走属性信息
     * @return ChannelAllowAttr|false
     * @date 2021/08/31
     * @author longli
     */
    public function addAllow($data = [])
    {
        $aData = ChannelAllowAttr::getFilterField($data);
        if(empty($aData)) return false;
        $aData = Tools::trim($aData);
        $allow = null;
        if(isset($aData['allow_id'])) $allow = ChannelAllowAttr::get($aData['allow_id']);
        if(!empty($allow))
        {
            $allow->save($aData);
        }
        else
        {
            $allow = ChannelAllowAttr::create($aData)->refresh();
        }
        return $allow;
    }

    /**
     * 申报订单获取追踪号和面单
     * @param int|Orders $order 订单 id 或者订单实体
     * @return bool
     * @date 2020/09/25
     * @author longli
     */
    public function declareOrder($order)
    {
        $order = Orders::getObj($order);
        if(empty($order)
            || !in_array($order->getData('order_status'), [Orders::ORDER_LOCK, Orders::ORDER_LACK, Orders::ORDER_WAIT_PUR, Orders::ORDER_WAIT_PUR_ING, Orders::ORDER_DECLARE_ERROR])
            || !($obj = $this->buildChannelClasses($order->channel_id))
        ) return false;
        $tempStatus = $order->getData('order_status');
        $order->order_status = Orders::ORDER_DECLARE_ING;
        $order->save();
        $obj->setOrder($order);
        $result = $obj->getTrackNumber() && $obj->getLabel();
        if(!$result) $obj->resetOrderStatus();
        // 如果是缺货状态将重新置回缺货
        if(in_array($tempStatus, [Orders::ORDER_LACK, Orders::ORDER_OUT_OF_STOCK, Orders::ORDER_WAIT_PUR, Orders::ORDER_WAIT_PUR_ING]))
        {
            $order->order_status = $tempStatus;
            $order->save();
        }
        if($result && $tempStatus == Orders::ORDER_DECLARE_ERROR && $order->getData('stock_status') == \app\common\model\WarehouseStock::STOCK_WAIT)
        {
            $order->order_status = Orders::ORDER_LACK;
            $order->save();
        }
        return $result;
    }

    /**
     * 取消申报订单
     * @param int $channelId 渠道 id
     * @param int|Orders $order 订单 id 或者订单实体
     * @return bool
     * @date 2020/09/25
     * @author longli
     */
    public function cancelOrder($channelId, $order)
    {
        if(!($obj = $this->buildChannelClasses($channelId))) return false;
        if(is_numeric($order)) $order = Orders::get($order);
        $order->channel_id = 0;
        $obj->setOrder($order);
        if($t = $obj->cancelOrder())
        {
            $obj->resetOrderStatus();
        }
        return $t;
    }

    /**
     * 构建渠道对接类
     * @param int|Channel $channel 渠道id, 或者渠道实体
     * @return bool|BaseChannel
     * @date 2020/09/25
     * @author longli
     */
    public function buildChannelClasses($channel)
    {
        if(is_numeric($channel)) $channel = Channel::get($channel);
        if(empty($channel)) return false;
        $classes = BaseChannel::getClasses($channel->carrier->classes);
        if(!class_exists($classes)) return false;
        try
        {
            return new $classes($channel->channel_id);
        }catch(\Exception $e)
        {
            Log::info($e->getMessage());
        }
        return false;
    }

    /**
     * 获取渠道面单尺寸大小
     * @param int|string 渠道id, 多个使用英文逗号分开
     * @return array
     * @date 2020/12/04
     * @author longli
     */
    public function getLabelSize($chIds)
    {
        $ret = [];
        foreach(Channel::field(["channel_id", "label_width", "label_height"])->whereIn("channel_id", $chIds)->select() as $channel)
        {
            $ret[$channel->channel_id] = [
                "label_width"  => $channel->label_width,
                "label_height" => $channel->label_height,
            ];
        }
        return $ret;
    }

    /**
     * 获取面单绝对路径
     * @param string $label 渠道1
     * @return string
     * @date 2020/12/04
     * @author longli
     */
    public function getLabelPath($label = '')
    {
        return self::getRootPath($label);
    }

    /**
     * 合并PDF
     * @param array $files 文件绝对路径
     * @param array $pageSize PDF尺寸，默认为 A4
     * @param string $output 输出路径带文件名，如果为空则直接输入出到浏览器
     * @return false|string
     * @date 2020/12/04
     * @author longli
     */
    public function mergePdf($files = [], $pageSize = [], $output = '')
    {
        $files = array_unique($files);
        $isEmptyFiles = true;
        foreach($files as $f)
        {
            if(is_file($f))
            {
                $isEmptyFiles = false;
                break;
            }
        }
        if($isEmptyFiles) return false;
        if(empty($pageSize)) $pageSize = '';
        $mpdf = new \Mpdf\Mpdf([
            'mode' => 'UTF-8',
            'format' => $pageSize,
            //'default_font_size' => 40,
            'default_font' => '',
            //'margin_left' => 20,
            //'margin_right' => 20
        ]);
        try
        {
            foreach($files as $file)
            {
                if(!is_file($file)) continue;
                $count = $mpdf->setSourceFile($file);
                for($i = 1; $i <= $count; $i++)
                {
                    $mpdf->addPage();
                    $tpId = $mpdf->importPage($i);
                    $mpdf->useTemplate($tpId);
                }
            }
            ob_end_clean();
            if(!empty($output))
            {
                $dir = dirname($output);
                if(!is_dir($dir)) mkdir($dir, 0777, true);
            }
            $mpdf->Output($output);
            return $output;
        }catch(\Exception $e)
        {
            Log::info($e->getMessage());
            return false;
        }
    }

    /**
     * 处理邮编
     * @param string $postCode 邮编
     * @return string
     * @date 2021/08/29
     * @author longli
     */
    public function postCodeRange($postCode = '')
    {
        if(empty($postCode)) return $postCode;
        $tempCode = Tools::trim(explode(',', replaceStr($postCode)));
        if(Tools::contains($postCode, '-'))
        {
            $t = [];
            $regex = '/\d+\-\d+/';
            foreach($tempCode as $k => $code)
            {
                if(!preg_match($regex, $code)) continue;
                $r = explode('-', $code);
                $t = array_merge($t, range($r[0], $r[1]));
                unset($tempCode[$k]);
            }
            $tempCode = array_merge($t, $tempCode);
        }
        return join(',', array_unique($tempCode));
    }
}